﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.IO.Ports;
using System.Text;
using System.Windows;

namespace SerialPortDebugTool;

public partial class MainWindowViewModel : ObservableObject
{
    /// <summary>
    /// 
    /// </summary>
    public MainWindowViewModel()
    {
        OpenBtnText = "打开串口";
        DataReceivedText = "数据接受区\n";
        var ports = SerialPort.GetPortNames() ?? [];
        PortNames.AddRange(ports);  // 获取电脑上可用串口号
        if (ports.Length > 0) SerialPortParameter!.PortName = ports[0];
        SerialPortParameter!.DataBit = "8";
        SerialPortParameter!.BaudRate = "9600";
        SerialPortParameter!.CheckBit = "无";
        SerialPortParameter!.StopBit = "1";
    }

    public SerialPort? SerialPort { get; set; } = new();

    #region 通知属性

    /// <summary>
    /// 端口号集合
    /// </summary>
    public List<string> PortNames { get; set; } = new();

    /// <summary>
    /// 串口参数
    /// </summary>
    private SerialPortParameter? serialPortParameter = new();

    public SerialPortParameter? SerialPortParameter
    {
        get { return serialPortParameter; }
        set { SetProperty(ref serialPortParameter, value); }
    }

    /// <summary>
    /// 打开串口文本
    /// </summary>
    private string? openBtnText;

    public string? OpenBtnText
    {
        get { return openBtnText; }
        set { SetProperty(ref openBtnText, value); }
    }

    /// <summary>
    /// 接收发送文本
    /// </summary>
    private string? dataReceivedText;

    public string? DataReceivedText
    {
        get { return dataReceivedText; }
        set { SetProperty(ref dataReceivedText, value); }
    }

    /// <summary>
    /// 是否16进制接收
    /// </summary>
    private bool is0XReceived = false;

    public bool Is0XReceived
    {
        get { return is0XReceived; }
        set { is0XReceived = value; }
    }

    /// <summary>
    /// 接收发送文本
    /// </summary>
    private string? sendDataText = "";

    public string? SendDataText
    {
        get { return sendDataText; }
        set { SetProperty(ref sendDataText, value); }
    }

    /// <summary>
    /// 是否16进制发送
    /// </summary>
    private bool is0XSend = false;

    public bool Is0XSend
    {
        get { return is0XSend; }
        set { is0XSend = value; }
    }

    #endregion

    #region 命令

    /// <summary>
    /// 打开串口
    /// </summary>
    [RelayCommand]
    private void OpenSerialPort()
    {
        if (OpenBtnText == "打开串口")
        {
            try
            {
                // 配置串口基本信息
                SerialPort.PortName = SerialPortParameter.PortName; // 端口号
                SerialPort.BaudRate = Convert.ToInt32(SerialPortParameter.BaudRate); // 波特率
                SerialPort.DataBits = Convert.ToInt32(SerialPortParameter.DataBit);  // 数据位
                SerialPort.StopBits = (StopBits)Convert.ToInt32(SerialPortParameter.StopBit);  // 停止位

                // 校验位
                if (SerialPortParameter.CheckBit == "无") SerialPort.Parity = Parity.None;
                else if (SerialPortParameter.CheckBit == "奇校验") SerialPort.Parity = Parity.Odd;
                else if (SerialPortParameter.CheckBit == "偶校验") SerialPort.Parity = Parity.Even;
                SerialPort.RtsEnable = true;
                SerialPort.ReceivedBytesThreshold = 1;
                SerialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
                SerialPort.Open();

                OpenBtnText = "关闭串口";

                MessageBox.Show("打开成功！", "提示");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开串口失败：{ex.ToString()}", "错误提示");
            }
        }
        else
        {
            try
            {
                SerialPort.Close();
                OpenBtnText = "打开串口";
                MessageBox.Show("关闭成功！", "提示");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"关闭串口失败：{ex.ToString()}", "错误提示");
            }
        }
    }

    /// <summary>
    /// 清除接收
    /// </summary>
    [RelayCommand]
    private void ClearDataReceived()
    {
        DataReceivedText = "";
    }

    /// <summary>
    /// 发送数据
    /// </summary>
    [RelayCommand]
    private void SendData()
    {
        if (SendDataText.Length <= 0) return;

        try
        {
            if (is0XSend)
            {
                var text = SendDataText.Replace(" ", "");
                int length = text.Length;

                // 偶数将字符拆分成01 02 03 04
                if (length % 2 == 0)
                {
                    byte[] returnBytes = new byte[(text.Length) / 2];
                    for (int i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(text.Substring(i * 2, 2), 16);
                    }
                    SerialPort.Write(returnBytes, 0, returnBytes.Length);
                }
                else
                {
                    byte[] returnBytes = new byte[(text.Length) / 2 + 1];
                    for (int i = 0; i < returnBytes.Length - 1; i++)
                    {
                        returnBytes[i] = Convert.ToByte(text.Substring(i * 2, 2), 16);
                    }
                    // 奇数最后一位补0
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(text.Substring(returnBytes.Length - 1, 1).PadLeft(2, '0'), 16);
                    SerialPort.Write(returnBytes, 0, returnBytes.Length);
                }
            }
            else
            {
                SerialPort.Write(SendDataText);
            }
        }
        catch (Exception)
        {

        }
    }

    /// <summary>
    /// 清除发送数据
    /// </summary>
    [RelayCommand]
    private void ClearSendData()
    {
        SendDataText = "";
    }

    #endregion

    #region 私有方法

    /// <summary>
    /// 数据接收
    /// </summary>
    private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        // 获取可以读取的字节数
        int len = SerialPort.BytesToRead;
        byte[] buff = new byte[len];
        SerialPort.Read(buff, 0, len);
        var action = () =>
        {
            if (Is0XReceived)
            {
                DataReceivedText += byteToHexStr(buff) + "\n";
            }
            else
            {
                string str = Encoding.Default.GetString(buff);
                DataReceivedText += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\n";
                DataReceivedText += str + "\n" + "\n";
            }
        };
        action.Invoke();
    }

    /// <字节数组转16进制字符串>
    /// <param name="bytes"></param>
    /// <returns> String 16进制显示形式</returns>
    public static string byteToHexStr(byte[] bytes)
    {
        string returnStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\n";
        try
        {
            if (bytes != null)
            {
                for (int i = 0; i < bytes.Length; i++)
                {
                    returnStr += bytes[i].ToString("X2");
                    returnStr += " ";//两个16进制用空格隔开,方便看数据
                }
            }
            return returnStr + "\n";
        }
        catch (Exception)
        {
            return returnStr + "\n";
        }
    }

    #endregion
}

public class SerialPortParameter
{
    /// <summary>
    /// 端口号
    /// </summary>
    public string? PortName { get; set; }

    /// <summary>
    /// 波特率
    /// </summary>
    public string? BaudRate { get; set; }

    /// <summary>
    /// 停止位
    /// </summary>
    public string? StopBit { get; set; }

    /// <summary>
    /// 数据位
    /// </summary>
    public string? DataBit { get; set; }

    /// <summary>
    /// 校验位
    /// </summary>
    public string? CheckBit { get; set; }
}
